#include "Socket.hpp"
#include "Log.hpp"
#include <poll.h>
#include <algorithm>
#include <memory>

using namespace Net_Work;

const static uint16_t defaultport = 8888;
const static int gbacklog = 8; // 维护的全连接队列
const static int gnum = 5;

class PollServer
{
private:
    void HandlerEvent()
    {
        for(int i = 0; i < _num; i++)
        {
            if(_rfds[i].fd == -1) continue;
            int fd = _rfds[i].fd;
            if(fd & POLLIN)
            {
                // 新连接到来
                if(fd == _listensock->GetSockFd())
                {
                    std::cout << "get a new connection" << std::endl;
                    std::string peerip;
                    uint16_t peerport;
                    int sockfd = _listensock->AcceptConnection(&peerip, &peerport);
                    if(sockfd == -1)
                    {
                        lg.LogMessage(Error, "accept failed\n");
                        continue;
                    }
                    lg.LogMessage(Info, "a new client, client info: %s:%d, fd: %d\n", peerip.c_str(), peerport, sockfd);
                    // 将新的文件描述符添加到poll的监听列表中
                    int pos = 0;
                    for(; pos < _num; pos++)
                    {
                        if(_rfds[i].fd != -1)
                        {
                            _rfds[i].fd = sockfd;
                            _rfds[i].events |= POLLIN;
                            lg.LogMessage(Info, "get a new connection, fd is: %d\n", sockfd);
                            break;
                        }
                    }
                    // 文件描述符个数达到监听列表上限，可以扩容
                    if(pos == _num)
                    {
                        close(sockfd);
                        lg.LogMessage(Warning, "server is full!\n");
                    }
                }
                // 新数据到来
                else
                {
                    char buffer[1024];
                    ssize_t n = recv(fd, buffer, sizeof(buffer) - 1, 0);
                    if(n > 0)
                    {
                        buffer[n] = 0;
                        lg.LogMessage(Info, "client say# %s\n", buffer);
                        std::string message = "你好呀，少年， ";
                        message += buffer;
                        send(fd, message.c_str(), message.size(), 0);
                    }
                    else
                    {
                        lg.LogMessage(Warning, "client quit, maybe quit or error\n");
                        close(fd);
                        _rfds[i].fd = -1;
                        _rfds[i].events = 0;
                        _rfds[i].revents = 0;
                    }
                }
            }    
        }
    }

public:
    PollServer(uint16_t port = defaultport) : _port(port), _listensock(new TcpSocket()), _isrunning(false), _num(gnum)
    {
    }

    void InitServer()
    {
        _listensock->BuildListenSocketMethod(_port, gbacklog);
        _rfds = new pollfd[_num];
        for(int i = 0; i < _num; i++)
        {
            _rfds[i].fd = -1;
            // 和select不一样，输入和输出分离了
            _rfds[i].events = 0; 
            _rfds[i].revents = 0;
        }
        // 最开始只有一个fd：_listensock
        _rfds[0].fd = _listensock->GetSockFd();
        _rfds[0].events |= POLLIN;
    }

    void Stop()
    {
        _isrunning = false;
    }

    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 设置超时时间
            int timeout = 1000;
            int n = poll(_rfds, _num, timeout);
            switch(n)
            {
                case 0:
                    lg.LogMessage(Info, "poll timeout, last time: %d ms\n", timeout);
                    break;
                case -1:
                    lg.LogMessage(Warning, "poll failed\n");
                    break;
                default:
                    lg.LogMessage(Info, "poll success, last time: %d ms\n", timeout);
                    HandlerEvent();
                    break;
            }
        }
        _isrunning = false;
    }
    void PrintDebug()
    {
        std::cout << "rfds list is: ";
        for(int i = 0; i < _num; i++)
        {
            if(_rfds[i].fd != -1)
            {
                std::cout << _rfds[i].fd << " ";
            }
        }
    }

private:
    std::unique_ptr<Socket> _listensock;
    uint16_t _port;
    bool _isrunning;
    struct pollfd* _rfds;
    int _num;
};